package com.ly.mp.dal.comm.jdbc;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;

import com.ly.mp.dal.comm.helper.PropertyResource;


public class DynamicCreateReadDataSource
        implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
    private static final Logger logger = LoggerFactory.getLogger(DynamicCreateReadDataSource.class);
    public static final String DATASOURCE_BEAN_CLASS = "com.alibaba.druid.pool.DruidDataSource";
    private ConfigurableApplicationContext app;
    private DynamicDataSource dynamicDataSource;

    public void setDataSource(DynamicDataSource dynamicDataSource) {
        this.dynamicDataSource = dynamicDataSource;
    }

    public void setApplicationContext(ApplicationContext app) throws BeansException {
        this.app = (ConfigurableApplicationContext) app;
    }

    public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            if (this.app == null) {
                return;
            }

            List<DataSourceInfo> dsList = this.getDatasourceList();
            if (dsList == null) {
                return;
            }

            this.addSourceBeanToApp(dsList);
        } catch (Exception var3) {
            logger.error("创建datasource Bean出错!", var3);
        }

    }

    private void addSourceBeanToApp(List<DataSourceInfo> datasources) {
        DefaultListableBeanFactory acf =
                (DefaultListableBeanFactory) this.app.getAutowireCapableBeanFactory();
        String databaseBeanClass = "com.alibaba.druid.pool.DruidDataSource";
        Map<Object, Object> targetDataSources = new LinkedHashMap();
        Iterator var6 = datasources.iterator();

        while (var6.hasNext()) {
            DataSourceInfo info = (DataSourceInfo) var6.next();
            String beanId = info.dbkey;
            BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(databaseBeanClass);
            bdb.getBeanDefinition().setAttribute("id", beanId);
            bdb.getBeanDefinition().setInitMethodName("init");
            bdb.getBeanDefinition().setDestroyMethodName("close");
            bdb.addPropertyValue("name", info.name);
            bdb.addPropertyValue("url", info.jdbcUrl);
            bdb.addPropertyValue("username", info.user);
            bdb.addPropertyValue("password", info.password);
            bdb.addPropertyValue("initialSize", PropertyResource.getProperty("druid.initialSize"));
            bdb.addPropertyValue("minIdle", PropertyResource.getProperty("druid.minIdle"));
            bdb.addPropertyValue("maxActive", PropertyResource.getProperty("druid.maxActive"));
            bdb.addPropertyValue("maxWait", PropertyResource.getProperty("druid.maxWait"));
            bdb.addPropertyValue("timeBetweenEvictionRunsMillis",
                    PropertyResource.getProperty("druid.timeBetweenEvictionRunsMillis"));
            bdb.addPropertyValue("minEvictableIdleTimeMillis",
                    PropertyResource.getProperty("druid.minEvictableIdleTimeMillis"));
            bdb.addPropertyValue("validationQuery",
                    info.dbType == 0 ? "select 'x' from dual" : "select 'x'");
            bdb.addPropertyValue("testWhileIdle",
                    PropertyResource.getProperty("druid.testWhileIdle"));
            bdb.addPropertyValue("testOnBorrow",
                    PropertyResource.getProperty("druid.testOnBorrow"));
            bdb.addPropertyValue("testOnReturn",
                    PropertyResource.getProperty("druid.testOnReturn"));
            bdb.addPropertyValue("poolPreparedStatements", info.dbType == 0);
            bdb.addPropertyValue("maxPoolPreparedStatementPerConnectionSize", PropertyResource
                    .getProperty("druid.maxPoolPreparedStatementPerConnectionSize"));
            bdb.addPropertyValue("filters", PropertyResource.getProperty("druid.filters"));
            // https://blog.csdn.net/time_poster/article/details/116539125
            acf.registerBeanDefinition(beanId, bdb.getBeanDefinition());
            targetDataSources.put(info.dbkey, this.app.getBean(beanId));
        }

        this.dynamicDataSource.setTargetDataSources(targetDataSources);
        this.dynamicDataSource.afterPropertiesSet();
    }

    private List<DataSourceInfo> getDatasourceList() throws Exception {
        List<DataSourceInfo> dsList = new ArrayList<>();

        for (int i = 0; i < this.dynamicDataSource.getReadDBSize(); ++i) {
            DataSourceInfo dsi = new DataSourceInfo();
            dsi.name = PropertyResource.getProperty("read.jdbc.name." + i);
            dsi.jdbcUrl = PropertyResource.getProperty("read.jdbc.url." + i);
            dsi.user = PropertyResource.getProperty("read.jdbc.username." + i);
            dsi.password = PropertyResource.getProperty("read.jdbc.password." + i);
            dsi.dbType = dsi.jdbcUrl.indexOf("mysql") == -1 ? 0 : 1;
            dsi.dbkey = "readDBKey" + i;
            dsList.add(dsi);
        }

        return dsList;
    }

    private class DataSourceInfo {
        public String dbkey;
        public String name;
        public int dbType;
        public String jdbcUrl;
        public String user;
        public String password;

        private DataSourceInfo() {}

        public String toString() {
            return "(dbType:" + this.dbType + "(url:" + this.jdbcUrl + ", username:" + this.user
                    + ", password:" + this.password + ")";
        }
    }
}
